package org.tio.sitexxx.im.server;

import java.io.IOException;

import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.state.ConnectionState;
import org.apache.curator.framework.state.ConnectionStateListener;
import org.apache.zookeeper.CreateMode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tio.cluster.TioClusterConfig;
import org.tio.cluster.redisson.RedissonTioClusterTopic;
import org.tio.flash.policy.server.FlashPolicyServerStarter;
import org.tio.server.ServerGroupContext;
import org.tio.server.TioServer;
import org.tio.server.intf.ServerAioHandler;
import org.tio.server.intf.ServerAioListener;
import org.tio.sitexxx.im.common.ImTioUuid;
import org.tio.sitexxx.im.server.handler.ImServerHandler;
import org.tio.sitexxx.im.server.init.TopicInit;
import org.tio.sitexxx.im.server.ws.ImWsStarter;
import org.tio.sitexxx.service.init.CacheInit;
import org.tio.sitexxx.service.init.JFInit;
import org.tio.sitexxx.service.init.JsonInit;
import org.tio.sitexxx.service.init.PropInit;
import org.tio.sitexxx.service.init.RedisInit;
import org.tio.sitexxx.service.init.ZkInit;
import org.tio.sitexxx.service.ip2region.Ip2RegionInit;
import org.tio.sitexxx.service.service.base.SensitiveWordsService;
import org.tio.sitexxx.service.tio.TioSiteIpStatListener;
import org.tio.sitexxx.service.vo.Const;
import org.tio.sitexxx.service.vo.LoadData;
import org.tio.utils.Threads;
import org.tio.utils.jfinal.P;
import org.tio.utils.json.Json;
import org.tio.utils.quartz.QuartzUtils;
import org.tio.utils.zk.Zk;

/**
 * 
 * @author tanyaowu 
 * 2016年9月8日 上午11:39:30
 */
public class TioSiteImServerStarter {
	private static Logger log = LoggerFactory.getLogger(TioSiteImServerStarter.class);

	public static ImTioUuid imTioUuid;

	public static PacketDispatcher packetDispatcher = null;

	public static ServerAioHandler			tioSiteImServerAioHandler	= null;
	public static ServerAioListener			tioSiteImServerAioListener	= null;
	public static TioSiteImGroupListener	tioSiteImGroupListener		= null;

	//绑定服务ip，一般用null
	public static String bindIp = null;//"127.0.0.1";
	
	//app
	public static ServerGroupContext	serverGroupContextApp	= null;
	public static TioServer				tioServerApp			= null;

	//WS
	public static ServerGroupContext	serverGroupContextWs	= null;
	public static ImWsStarter			imWsStarter				= null;


	/**
	 * @param args
	 *
	 * @author tanyaowu
	 * @throws IOException
	 * 2016年11月17日 下午5:59:24
	 *
	 */
	public static void main(String[] args) throws Exception {
		try {
			// 属性初始化
			PropInit.init();

			// ip2region初始化
			Ip2RegionInit.init();

			// 敏感词初始化
			SensitiveWordsService.init();

			// Json配置初始化
			JsonInit.init();

			// jfinal 初始化
			JFInit.init();

			// 缓存初始化
			CacheInit.init();

			// redis初始化，里面会有topic等的初始化
			RedisInit.init();

			TopicInit.init();

			//先启动聊天服务器，再启动zk
			imServerInit();

			FlashPolicyServerStarter.start(null, null, Threads.getTioExecutor(), Threads.getGroupExecutor());

			// zookeeper初始化
			ZkInit.init(null);

			Zk.zkclient.getConnectionStateListenable().addListener(new ConnectionStateListener() {
				@Override
				public void stateChanged(CuratorFramework client, ConnectionState newState) {
					if (newState == ConnectionState.CONNECTED) {
						//创建相关节点
						try {
							String myip = org.tio.sitexxx.service.vo.Const.SERVICE_HOST;
							String mypath = Const.ZkNode.IM_SERVERS + "/" + myip;
							LoadData loadData = Ims.createLoadData();
							Zk.createOrUpdate(mypath, Json.toJson(loadData), CreateMode.EPHEMERAL);
						} catch (Exception e) {
							log.error(e.toString(), e);
						}
					}
				}
			});
			Zk.start();

			//启动定时任务，配置文件在：config/tio-quartz.properties
			QuartzUtils.start();

		} catch (Throwable e) {
			log.error(e.toString(), e);
			System.exit(1);
		}

	}

	public static void imServerInit() throws Exception {
		packetDispatcher = new PacketDispatcher(new String[] { ImServerHandler.class.getPackage().getName() });

		tioSiteImServerAioHandler = new TioSiteImServerAioHandler(packetDispatcher);
		tioSiteImServerAioListener = TioSiteImServerAioListener.me;
		tioSiteImGroupListener = TioSiteImGroupListener.me;
		serverGroupContextApp = new ServerGroupContext("Tio Site App Im Server", tioSiteImServerAioHandler, tioSiteImServerAioListener, Threads.getTioExecutor(),
		        Threads.getGroupExecutor());
		serverGroupContextApp.logWhenDecodeError = P.getBoolean("im.logWhenDecodeError", false);

		serverGroupContextApp.groups.setChannelContextComparator(ChannelContextComparator.me);
		long workerId = P.getLong("uuid.workerid");
		long datacenterId = P.getLong("uuid.datacenter");
		imTioUuid = new ImTioUuid(workerId, datacenterId);

		boolean isGroupCluster = false;//P.getBoolean("im.group.cluster", false);

		//启动给App用的服务器
		TioClusterConfig tioClusterConfigApp = new TioClusterConfig(new RedissonTioClusterTopic("app", RedisInit.get()));
		tioClusterConfigApp.setCluster4group(isGroupCluster);
		serverGroupContextApp.setTioClusterConfig(tioClusterConfigApp);
		serverGroupContextApp.setTioUuid(imTioUuid);
		serverGroupContextApp.setGroupListener(tioSiteImGroupListener);
		serverGroupContextApp.setIpStatListener(TioSiteIpStatListener.app);
		serverGroupContextApp.ipStats.addDurations(Const.IpStatDuration.IPSTAT_DURATIONS);
		useSsl(serverGroupContextApp);

		tioServerApp = new TioServer(serverGroupContextApp);
		
		
		//启动websocket服务器
		imWsStarter = new ImWsStarter(Const.ImPort.WS, imTioUuid, packetDispatcher);
		serverGroupContextWs = imWsStarter.getServerGroupContext();
		serverGroupContextWs.logWhenDecodeError = P.getBoolean("im.ws.logWhenDecodeError", false);
		serverGroupContextWs.groups.setChannelContextComparator(ChannelContextComparator.me);
		serverGroupContextWs.setName("Tio Site WS Im Server");

		TioClusterConfig tioClusterConfigWs = new TioClusterConfig(new RedissonTioClusterTopic("ws", RedisInit.get()));
		tioClusterConfigWs.setCluster4group(isGroupCluster);
		serverGroupContextWs.setTioClusterConfig(tioClusterConfigWs);
		serverGroupContextWs.setIpStatListener(TioSiteIpStatListener.ws);
		serverGroupContextWs.ipStats.addDurations(Const.IpStatDuration.IPSTAT_DURATIONS);
		useSsl(serverGroupContextWs);

		serverGroupContextWs.share(serverGroupContextApp);
		serverGroupContextWs.packetConverter = ImToWsPacketConverter.me;

		tioServerApp.start(bindIp, Const.ImPort.APP);
		imWsStarter.start();
	}

	private static void useSsl(ServerGroupContext serverGroupContext) throws Exception {
		String keyStoreFile = P.get("ssl.keystore", null);
		String trustStoreFile = P.get("ssl.truststore", null);
		String keyStorePwd = P.get("ssl.pwd", null);
		serverGroupContext.useSsl(keyStoreFile, trustStoreFile, keyStorePwd);
	}

	public TioSiteImServerStarter() {

	}

}
